package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func main1111() {
	// 获取当前工作目录作为默认值
	currentDir, err := os.Getwd()
	if err != nil {
		fmt.Printf("警告: 无法获取当前工作目录: %v\n", err)
		currentDir = "."
	}

	currentDir = `D:\\code\\go\\gozrd-admin-api\\internal\\entity`

	// 定义命令行参数，设置默认值
	inputDir := flag.String("dir", currentDir, "输入目录路径 (默认: 当前目录)")
	outputFile := flag.String("out", "read_data.txt", "输出文件路径 (默认: read_data.txt)")
	appendMode := flag.Bool("append", false, "追加模式 (默认: 覆盖)")
	extensions := flag.String("ext", "", "仅包含指定扩展名的文件，用逗号分隔 (如: .go,.txt)")
	excludeDirs := flag.String("exclude-dir", "", "排除的目录名，用逗号分隔 (如: .git,node_modules)")
	excludeFiles := flag.String("exclude-file", "", "排除的文件名，用逗号分隔 (如: README.md,LICENSE)")
	showHelp := flag.Bool("help", false, "显示帮助信息")

	// 解析命令行参数
	flag.Parse()

	// 显示帮助信息并退出
	if *showHelp {
		fmt.Println("目录文件合并工具 - 将目录下的所有文件内容合并到一个文件中")
		fmt.Println("\n用法:")
		flag.PrintDefaults()
		fmt.Println("\n示例:")
		fmt.Println("  mergedir                              # 合并当前目录下所有文件到read_data.txt")
		fmt.Println("  mergedir -dir /path/to/src            # 合并指定目录下所有文件到read_data.txt")
		fmt.Println("  mergedir -out output.txt              # 合并当前目录下所有文件到output.txt")
		fmt.Println("  mergedir -ext .go,.txt                # 仅合并.go和.txt文件")
		fmt.Println("  mergedir -exclude-dir .git,tmp        # 排除.git和tmp目录")
		fmt.Println("  mergedir -append                      # 追加到输出文件而不是覆盖")
		os.Exit(0)
	}

	// 解析要排除的目录
	excludeDirList := []string{}
	if *excludeDirs != "" {
		excludeDirList = strings.Split(*excludeDirs, ",")
	}

	// 解析要排除的文件
	excludeFileList := []string{}
	if *excludeFiles != "" {
		excludeFileList = strings.Split(*excludeFiles, ",")
	}

	// 解析扩展名过滤
	extensionList := []string{}
	if *extensions != "" {
		extensionList = strings.Split(*extensions, ",")
		// 确保扩展名都有点前缀
		for i, ext := range extensionList {
			if !strings.HasPrefix(ext, ".") {
				extensionList[i] = "." + ext
			}
		}
	}

	// 确保输入目录存在
	info, err := os.Stat(*inputDir)
	if err != nil {
		fmt.Printf("错误: 无法访问输入目录 '%s': %v\n", *inputDir, err)
		os.Exit(1)
	}
	if !info.IsDir() {
		fmt.Printf("错误: '%s' 不是一个目录\n", *inputDir)
		os.Exit(1)
	}

	// 创建或打开输出文件
	var outFile *os.File
	if *appendMode {
		outFile, err = os.OpenFile(*outputFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			fmt.Printf("错误: 无法打开输出文件进行追加 '%s': %v\n", *outputFile, err)
			os.Exit(1)
		}
	} else {
		outFile, err = os.Create(*outputFile)
		if err != nil {
			fmt.Printf("错误: 无法创建输出文件 '%s': %v\n", *outputFile, err)
			os.Exit(1)
		}
	}
	defer outFile.Close()

	// 写入合并头部信息
	startTime := time.Now().Format("2006-01-02 15:04:05")
	headerInfo := fmt.Sprintf("===== 文件合并开始于: %s =====\n", startTime)
	headerInfo += fmt.Sprintf("===== 输入目录: %s =====\n", *inputDir)
	headerInfo += fmt.Sprintf("===== 输出文件: %s =====\n\n", *outputFile)
	outFile.WriteString(headerInfo)

	// 计数器
	fileCount := 0
	totalBytes := int64(0)
	skippedCount := 0

	fmt.Printf("开始处理目录: %s\n", *inputDir)
	fmt.Printf("输出文件: %s (%s模式)\n\n", *outputFile, map[bool]string{true: "追加", false: "覆盖"}[*appendMode])

	// 遍历目录
	err = filepath.Walk(*inputDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			fmt.Printf("警告: 访问 '%s' 时出错: %v\n", path, err)
			return nil // 继续处理其他文件
		}

		// 跳过目录，但检查是否在排除列表中
		if info.IsDir() {
			dirName := filepath.Base(path)
			for _, excluded := range excludeDirList {
				if dirName == excluded {
					fmt.Printf("跳过目录: %s\n", path)
					return filepath.SkipDir // 跳过整个目录
				}
			}
			return nil
		}

		// 检查文件名是否在排除列表中
		fileName := filepath.Base(path)
		for _, excluded := range excludeFileList {
			if fileName == excluded {
				fmt.Printf("跳过文件: %s (文件名匹配排除规则)\n", path)
				skippedCount++
				return nil
			}
		}

		// 检查扩展名过滤
		if len(extensionList) > 0 {
			ext := strings.ToLower(filepath.Ext(path))
			matched := false
			for _, allowedExt := range extensionList {
				if ext == allowedExt {
					matched = true
					break
				}
			}
			if !matched {
				skippedCount++
				return nil // 不处理不匹配的文件
			}
		}

		// 跳过输出文件本身，防止无限增长
		absOutPath, _ := filepath.Abs(*outputFile)
		absPath, _ := filepath.Abs(path)
		if absOutPath == absPath {
			fmt.Printf("跳过输出文件: %s\n", path)
			return nil
		}

		// 获取文件的绝对路径
		absPath, err = filepath.Abs(path)
		if err != nil {
			absPath = path // 如果获取绝对路径失败，使用原始路径
		}

		// 写入文件头部信息
		header := fmt.Sprintf("\n\n===== 文件: %s =====\n\n", absPath)
		_, err = outFile.WriteString(header)
		if err != nil {
			fmt.Printf("警告: 写入文件头失败 '%s': %v\n", path, err)
			return nil
		}

		// 打开源文件
		file, err := os.Open(path)
		if err != nil {
			fmt.Printf("警告: 无法打开文件 '%s': %v\n", path, err)
			return nil // 继续处理其他文件
		}
		defer file.Close()

		// 复制文件内容
		written, err := io.Copy(outFile, file)
		if err != nil {
			fmt.Printf("警告: 读取文件 '%s' 时出错: %v\n", path, err)
			return nil
		}

		fileCount++
		totalBytes += written
		fmt.Printf("处理文件: %s (%d 字节)\n", path, written)

		return nil
	})

	if err != nil {
		fmt.Printf("错误: 遍历目录时出错: %v\n", err)
		os.Exit(1)
	}

	// 写入结束标记
	endTime := time.Now().Format("2006-01-02 15:04:05")
	footer := fmt.Sprintf("\n\n===== 合并结束于: %s =====\n", endTime)
	outFile.WriteString(footer)

	fmt.Printf("\n完成! 合并了 %d 个文件，跳过了 %d 个文件，总共写入 %d 字节到 '%s'\n",
		fileCount, skippedCount, totalBytes, *outputFile)
}
